package main

import (
	"bufio"
	"encoding/json"
	"log"
	"os"
	"strconv"
	"strings"
	"sync/atomic"
	"time"

	"gitee.com/fcsvr/fc/fclog"
	"github.com/go-resty/resty/v2"
	"github.com/tidwall/gjson"
)

/*
func SnipeAlpha(alpha string, neut string, decay int, trunc float64) {
	simulateData := SimulateAlphaData{
		Type: "REGULAR",
		Settings: AlphaSetting{
			InstrumentType: "EQUITY",
			Region:         "USA",
			Universe:       "TOP3000",
			Delay:          1,
			Decay:          decay,
			Neutralization: neut,
			//Neutralization: "MARKET",
			//Neutralization: "SUBINDUSTRY",
			Truncation:     trunc,
			Pasteurization: "ON",
			UnitHandling:   "VERIFY",
			NanHandling:    "OFF",
			Language:       "FASTEXPR",
			Visualization:  false,
		},
		Regular: "",
	}
	//for G_Count < G_AlphaLen-1 {
	fclog.Debug("Snipe alpha = %s", alpha)
	count := 1
	simulateData.Regular = alpha
	simulateJson, _ := json.Marshal(simulateData)

	retry_num := G_RetryNum
	simProgressUrl := ""
	var resp *resty.Response

	for retry_num > 0 {
		resp, _ = G_Client.R().SetHeader("Content-Type", "application/json").SetBody(simulateJson).Post("https://api.worldquantbrain.com/simulations")
		//fmt.Println("header: ", resp.Header())
		//fmt.Println("body: ", string(resp.Body()))
		header, exists := resp.Header()["Location"]
		if exists {
			simProgressUrl = header[0]
			//fclog.Info("simProgressUrl: %s", simProgressUrl)

			for {
				resp, _ = G_Client.R().SetHeader("Content-Type", "application/json").Get(simProgressUrl)
				if _, exists := resp.Header()["Retry-After"]; !exists {
					time.Sleep(time.Second * 2)
					break
				}
			}
			strBody := string(resp.Body())
			alphaID := gjson.Get(strBody, "alpha").String()

			if alphaID == "" {
				fclog.Warn("Simulate Index = %d, AlphaID = Null, Body = %v, code = %v", count, resp.String(), resp.StatusCode())
			} else {
				fclog.Info("Simulate Index = %d, AlphaID = %s, go to Check", count, alphaID)
				CheckAlpha(int(1), alphaID)
			}
			fclog.Info("Snipe Alpha ID: %s", alphaID)

			break
		} else {
			fclog.Error("Snipe, No Location, Response Status Code: %v,%v, Retry_num = %d", resp.StatusCode(), resp.String(), retry_num)
		}
		if resp.StatusCode() == int(429) {
			time.Sleep(time.Minute * time.Duration(G_RetryNum-retry_num+1))
		} else if resp.StatusCode() == int(401) {
			G_Client.R().SetBasicAuth(G_User, G_Pswd).Post("https://api.worldquantbrain.com/authentication")
			time.Sleep(time.Second * 5)
		} else {
			fclog.Error("Response Status Code: %v, %v", resp.StatusCode(), resp.String())
			time.Sleep(time.Minute)
		}
		retry_num -= 1
		if retry_num == 0 {
			fclog.Error("Retry num: %d,  Response Status Code: %v, %v", retry_num, resp.StatusCode(), resp.String())
		}
	}
	//}
}

func SimulateAlpha() {
	simulateData := SimulateAlphaData{
		Type: "REGULAR",
		Settings: AlphaSetting{
			InstrumentType: "EQUITY",
			Region:         "USA",
			Universe:       "TOP3000",
			Delay:          1,
			Decay:          0,
			Neutralization: "INDUSTRY",
			Truncation:     0.05,
			Pasteurization: "ON",
			UnitHandling:   "VERIFY",
			NanHandling:    "OFF",
			MaxTrade:       "ON",
			Language:       "FASTEXPR",
			Visualization:  false,
		},
		Regular: "",
	}
	for G_Count < G_AlphaLen-1 {
		//G_MU.Lock()
		count := atomic.AddInt32(&G_Count, 1)
		express := G_AlphaExpress[count]
		decay := G_AlphaDecay[count]
		//G_MU.Unlock()
		simulateData.Regular = express
		simulateData.Settings.Decay = decay
		simulateData.Settings.Neutralization = G_AlphaNeut[count]
		simulateData.Settings.Region = G_AlphaRegion[count]
		fclog.Info("Index: %d, %s, %s", count, express, simulateData.Settings.Region)
		simulateData.Settings.Universe = G_AlphaUniverse[count]
		simulateJson, _ := json.Marshal(simulateData)

		retry_num := G_RetryNum
		simProgressUrl := ""
		var resp *resty.Response

		for retry_num > 0 {
			resp, _ = G_Client.R().SetHeader("Content-Type", "application/json").SetBody(simulateJson).Post("https://api.worldquantbrain.com/simulations")
			//fmt.Println("header: ", resp.Header())
			//fmt.Println("body: ", string(resp.Body()))
			header, exists := resp.Header()["Location"]
			if exists {
				simProgressUrl = header[0]

				for {
					resp, _ = G_Client.R().SetHeader("Content-Type", "application/json").Get(simProgressUrl)
					if _, exists := resp.Header()["Retry-After"]; !exists {
						break
					}
					time.Sleep(time.Second * 2)
				}

				strBody := string(resp.Body())
				alphaID := gjson.Get(strBody, "alpha").String()

				if alphaID == "" {
					fclog.Warn("Simulate Index = %d, AlphaID = Null, Body = %v, code = %v", count, resp.String(), resp.StatusCode())
					//time.Sleep(time.Minute)
				} else {
					fclog.Info("Simulate Index = %d, AlphaID = %s, go to Check", count, alphaID)
					go CheckAlpha(int(count), alphaID)
				}

				break
			} else {
				fclog.Info("Simulate Index: %d, No Location, Response Status Code: %v,%v, Retry_num = %d", count, resp.StatusCode(), resp.String(), retry_num)
			}
			if resp.StatusCode() == int(429) {
				time.Sleep(time.Minute * time.Duration(G_RetryNum-retry_num+1))
			} else if resp.StatusCode() == int(401) {
				G_Client.R().SetBasicAuth(G_User, G_Pswd).Post("https://api.worldquantbrain.com/authentication")
				time.Sleep(time.Second * 5)
			} else {
				fclog.Error("Simulate Index: %d, Response Status Code: %v, %v", count, resp.StatusCode(), resp.String())
				time.Sleep(time.Minute)
			}
			retry_num -= 1
			if retry_num == 0 {
				fclog.Error("Simulate Index: %d, Retry num: %d,  Response Status Code: %v, %v", count, retry_num, resp.StatusCode(), resp.String())
			}
		}

	}
	G_WaitGroup.Done()
}
*/

func SimulatePool() {
	for i := 0; i < G_Conf.SimulateNum; i++ {
		G_WaitGroup.Add(1)
		go MultiSimulateAlpha()
		//go Test()
	}
	G_WaitGroup.Wait()
}

func MultiSimulateAlpha() {
	simulateData := SimulateAlphaData{
		Type: "REGULAR",
		Settings: AlphaSetting{
			InstrumentType: "EQUITY",
			Region:         "USA",
			Universe:       "TOP3000",
			Delay:          1,
			Decay:          0,
			Neutralization: "INDUSTRY",
			Truncation:     0.05,
			Pasteurization: "ON",
			UnitHandling:   "VERIFY",
			NanHandling:    "OFF",
			MaxTrade:       "ON",
			Language:       "FASTEXPR",
			Visualization:  false,
		},
		Regular: "",
	}
	simulateList := make([]SimulateAlphaData, 0, 0)
	countList := make([]int, 0, 0)
	listCount := 0
	fclog.Debug("MultiSimulateAlpha, %d, %d", G_Count, G_AlphaLen)
	for G_Count < G_AlphaLen-1 {
		count := atomic.AddInt32(&G_Count, 1)
		countList = append(countList, int(count))
		regular := G_SimulateData[count].Regular
		fclog.Info("Index: %d, %s", count, regular)
		simulateData.Regular = regular
		simulateData.Settings.Decay = G_SimulateData[count].Settings.Decay
		simulateData.Settings.Neutralization = G_SimulateData[count].Settings.Neutralization
		simulateData.Settings.Region = G_SimulateData[count].Settings.Region
		simulateData.Settings.Universe = G_SimulateData[count].Settings.Universe

		simulateList = append(simulateList, simulateData)

		if (listCount < G_Conf.AlphaPoolNum-1) && (G_Count < G_AlphaLen) {
			listCount++
			continue
		}
		simulateJson, _ := json.Marshal(simulateList)

		retry_num := G_RetryNum
		simProgressUrl := ""
		var resp *resty.Response

		for retry_num > 0 {
			resp, _ = G_Client.R().SetHeader("Content-Type", "application/json").SetBody(simulateJson).Post("https://api.worldquantbrain.com/simulations")
			//fmt.Println("header: ", resp.Header())
			//fmt.Println("body: ", string(resp.Body()))
			header, exists := resp.Header()["Location"]
			if exists {
				simProgressUrl = header[0]

				for {
					resp, _ = G_Client.R().SetHeader("Content-Type", "application/json").Get(simProgressUrl)
					if resp.StatusCode() == int(401) {
						G_Client.R().SetBasicAuth(G_User, G_Pswd).Post("https://api.worldquantbrain.com/authentication")
						time.Sleep(time.Second * 5)
						continue
					}
					//fclog.Debug("Simulate Result strHeader = %v", resp.Header())
					if _, exists := resp.Header()["Retry-After"]; !exists {
						if _, e := resp.Header()["Allow"]; e {
							break
						}
					}
					time.Sleep(time.Second * 2)
				}

				//strHeader := string(resp.Header())
				fclog.Debug("Simulate Result strHeader = %v", resp.Header())
				strBody := string(resp.Body())
				fclog.Debug("Simulate Result strBody = %s", strBody)
				childrenJson := gjson.Get(strBody, "children")
				fclog.Debug("String len = %d", len(childrenJson.String()))
				if len(childrenJson.String()) == 0 {
					break
				}
				childrenResult := gjson.Parse(childrenJson.String()).Array()
				childrenLen := len(childrenResult)
				fclog.Debug("Simulate Result childrenLen = %v, %v", childrenLen, childrenResult[0])

				for i := 0; i < childrenLen; i++ {
					simUrl := "https://api.worldquantbrain.com/simulations/" + childrenResult[i].String()
					simuResp, _ := G_Client.R().SetHeader("Content-Type", "application/json").Get(simUrl)
					//fclog.Debug("Simulate Result simuResp = %v\n%v\n%v", simuResp.StatusCode(), simuResp.Header(), string(simuResp.Body()))
					alphaID := gjson.Get(string(simuResp.Body()), "alpha").String()
					count := countList[i]
					if alphaID != "" {
						fclog.Info("Simulate Index = %d, AlphaID = %s, go to Check", count, alphaID)
						go CheckAlpha(count, alphaID)
					}
				}

				break
			} else {
				fclog.Info("Simulate Index: %d, No Location, Response Status Code: %v,%v, Retry_num = %d", count, resp.StatusCode(), resp.String(), retry_num)
			}
			if resp.StatusCode() == int(429) {
				time.Sleep(time.Minute * time.Duration(G_RetryNum-retry_num+1))
			} else if resp.StatusCode() == int(401) {
				G_Client.R().SetBasicAuth(G_User, G_Pswd).Post("https://api.worldquantbrain.com/authentication")
				time.Sleep(time.Second * 5)
			} else {
				fclog.Error("Simulate Index: %d, Response Status Code: %v, %v", count, resp.StatusCode(), resp.String())
				time.Sleep(time.Minute)
			}
			retry_num -= 1
			if retry_num == 0 {
				fclog.Error("Simulate Index: %d, Retry num: %d,  Response Status Code: %v, %v", count, retry_num, resp.StatusCode(), resp.String())
			}
		}
		listCount = 0
		simulateList = make([]SimulateAlphaData, 0, 0)
		countList = make([]int, 0, 0)
	}
	G_WaitGroup.Done()
}

func ConstructAlphaExpressFromFile(filepath string) {
	file, err := os.Open(filepath)
	if err != nil {
		log.Println(err)
		return
	}
	defer file.Close()

	simulateDate := SimulateAlphaData{}
	scanner := bufio.NewScanner(file)
	scanner.Split(bufio.ScanLines)
	for scanner.Scan() {
		line := scanner.Text()
		line = strings.ReplaceAll(line, " ", "")
		parts := strings.Split(line, G_Split)
		//fclog.Debug("line = %s", line)
		//fclog.Debug("parts = %v, %v, %v", parts[1], parts[2], parts[3])
		simulateDate.Regular = parts[1]
		decay, _ := strconv.Atoi(parts[2])
		simulateDate.Settings.Decay = decay
		//fclog.Debug("decay = %d", decay)
		simulateDate.Settings.Neutralization = parts[3]
		simulateDate.Settings.Region = parts[4]
		simulateDate.Settings.Universe = parts[5]
		G_SimulateData = append(G_SimulateData, simulateDate)
	}
	G_AlphaLen = int32(len(G_SimulateData))
}
